package cn.maiyar.gateway.nacos;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.maiyar.gateway.NacosRoutesProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Nacos 路由数据源
 *
 * @author c.c
 */
@Slf4j
@RefreshScope
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private final ConfigService configService;

    private final ApplicationEventPublisher publisher;

    private final NacosRoutesProperties gatewayProperties;

    public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosRoutesProperties gatewayProperties, ConfigService configService) {
        this.publisher = publisher;
        this.gatewayProperties = gatewayProperties;
        this.configService = configService;
        this.addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            String content = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroupId(), gatewayProperties.getTimeout());
            log.debug("Nacos Route Config Data: {}", content);
            List<RouteDefinition> routeDefinitions = getListByStr(content);
            return Flux.fromIterable(routeDefinitions);
        } catch (NacosException e) {
            log.error("Nacos Route Config Data Error :", e);
        }
        return Flux.fromIterable(CollUtil.newArrayList());
    }

    /*** 添加Nacos监听*/
    private void addListener() {
        try {
            configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroupId(), new Listener() {

                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    publisher.publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            log.error("Nacos Route Listener Error:", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    private List<RouteDefinition> getListByStr(String content) {
        if (StrUtil.isNotEmpty(content)) {
            return JSONUtil.toList(content, RouteDefinition.class);
        }
        return new ArrayList<>(0);
    }
}
